#if !defined(SM__CONFIG_H)
#define SM__CONFIG_H

#include "expat.h"
#include <string>
#include <map>
#include <vector>
#include <list>
#include <iostream>
using namespace std;

struct XMLNode;

typedef vector<XMLNode*> NodeArray;
typedef map<string,string>::iterator AttrIter;
typedef vector<XMLNode*>::iterator NodeIter;

// TO DO:  Figure out how text nodes are supposed to work ... at the moment
// they do not (and consequently, our XML format cannot have them).

// For the XML entity <sprite id="blah" />, we have an XMLNode where
// - tagName = "sprite"
// - attr["id"] = "blah"
struct XMLNode {
  string tagName;  
  map<string,string> attr; 
  vector<XMLNode*> children;
  XMLNode* parentNode;
  string textContent;
    
  XMLNode() : parentNode(NULL), tagName(""), textContent("") {
  }
  ~XMLNode() { // deletes the children nodes
    parentNode = NULL;
    for(NodeIter it = children.begin(); it != children.end(); ++it) {
      if(*it) { delete *it; *it = NULL; }
    }
    children.clear();
  }

  // NOTE: this will create an empty id attribute if it didn't exist
  const string& id() { return attr["id"]; }

  // finds the first element matching the input ID
  // returns NULL if no element found
  XMLNode* getElementById(const char* elemID) {
    if(id() == elemID) { return this; }

    XMLNode* node = NULL;
    for(NodeIter it = children.begin(); it != children.end(); ++it) {
      node = (*it)->getElementById(elemID);
      if(node) break;
    }
    return node;
  }

  // returns the first element matching the tag name
  XMLNode* getElementByTagName(const char* _tagName) {
    if(tagName == _tagName) { return this; }
    XMLNode* retNode = NULL;
    for(NodeIter it = children.begin(); it != children.end(); ++it) {
      retNode = (*it)->getElementByTagName(_tagName);
      if(retNode) { break; }
    }
    return retNode;
  }

  // if outArr is not NULL, this function appends all matching elements to outArr 
  // returns the number of elements found of that tagname
  int getElementsByTagName(const char* _tagName, NodeArray* outArr) {
    int retVal = 0;
    if(tagName == _tagName) { 
      if(outArr) { outArr->push_back(this); }
      ++retVal;
    }
    for(NodeIter it = children.begin(); it != children.end(); ++it) {
      retVal += (*it)->getElementsByTagName(_tagName, outArr);
    }
    return retVal;
  }

  bool hasChildNodes() const { return !children.empty(); }
};

// helper macros
#define ATOI(inStr) atoi(inStr.c_str())

#endif // SM__CONFIG_H
